﻿using System;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Forms;

using Microsoft.Win32;

using QuickTuner.Properties;

namespace QuickTuner
{
    internal static partial class Program
    {
        // this method is run only once the first time
        // QuickTuner is installed or upgraded
        private static void firstRun()
        {
            // check and configure IsolatedStorage
#if !PROFILING
            configureStorage();
#endif

            // backward compatibility checks
            ensureRadioHasVersionTag();
            ensureStationHasOrdinals();

            // check and configure radio protocol
            configureRadioProtocol();

        }

        private static void configureStorage()
        {
            var store = Storage.GetStore();

            // upgrade version 0.8.1.* to 0.8.2.*
            // changes radio serialization format from XML to binary
            // so we need to upgrade the xml file to binary format
            if (store.GetFileNames("radio.xml").Length > 0) {

                // load old xml format
                var file = new IsolatedStorageFileStream("radio.xml", FileMode.Open, store);
                var radio = Radio.LoadFrom(file);
                file.Close();
                file.Dispose();

                // save new binary format
                file = new IsolatedStorageFileStream("radio.bin", FileMode.CreateNew, store);
                radio.SaveBinaryTo(file);
                file.Close();
                file.Dispose();

                // delete the old format only if saving binary format is successful
                store.DeleteFile("radio.xml");
            }

        }


        /// <summary>
        /// Verify, initialize and update the radio:// protocol support
        /// to use the most recent QuickTuner exe
        /// </summary>
        private static void configureRadioProtocol()
        {
            var r = Registry.ClassesRoot.OpenSubKey("radio");

            // the base radio key exists?
            if (r == null)
                goto install;

            // verify the base radio key
            if (string.IsNullOrEmpty(r.GetValue(null) as string) || r.GetValue("URL Protocol") == null)
                goto install;

            // lambdarians are here
            Func<string, bool> check = key => (r = r.OpenSubKey(key)) != null;

            // verify the subsequent shell/open/command key
            if (check("shell") && check("open") && check("command")) {
                // check the "command" key value
                var curHandler = r.GetValue(null) as string;
                var curExe = Application.ExecutablePath;

                if (!string.IsNullOrEmpty(curHandler) && !curHandler.StartsWith(curExe))
                    goto install;

            } else
                goto install;

            return;

        install:

            // ask the user first wether its ok to install something into the registry
            var confirm = MessageBox.Show(
                "QuickTuner will now try to install support for radio:// URLs.\n\n" +
                    "Please click OK and then YES to proceed, otherwise click Cancel.",
                "QuickTuner",
                MessageBoxButtons.OKCancel);

            // if user's ok, proceed with install
            if (confirm == DialogResult.OK)
                installRadioProtocol();
        }

        /// <summary>
        /// Attemp to install the radio protocol and this EXE as the protocol handler
        /// </summary>
        private static void installRadioProtocol()
        {
            // fetch the templated registry file
            var radioReg = Resources.radio_protocol_reg;

            // fill in the template blanks
            var exe = Application.ExecutablePath
                .Replace("\\", @"\\")
                .Replace("\"", @"\""");

            radioReg = string.Format(radioReg, exe);

            // execute the file to add registry content to user machine
            // this is required to be run externally due to UAC and ClickOnce limitations

            var tempFilename = Path.ChangeExtension(Path.GetTempFileName(), ".reg");
            File.WriteAllText(tempFilename, radioReg);

            var p = Process.Start(tempFilename);
            if (p == null) return;

            p.WaitForExit();
            p.Dispose();

            File.Delete(tempFilename);
        }


        // backward-compatibility checks ________________________________________________

        /// <summary>
        /// Assign a version tag to the radio, if none exists
        /// </summary>
        private static void ensureRadioHasVersionTag()
        {

            var radio = Storage.LoadRadio();
            var ver = radio.ClientVersion;

            // has a version been added?
            if (ver != null) return;

            // the last version without the version tag is 0.8.3.32
            // we tag it to this version so it'll also receive all
            // the upgrades since that version as well.
            radio.ClientVersion = new Version(0, 8, 3, 32);
            Storage.SaveRadio(radio);
        }

        /// <summary>
        /// Assign UserOrdinal to stations if upgraded from version earlier than 0.8.3
        /// </summary>
        private static void ensureStationHasOrdinals()
        {
            // load the radio data file
            if (!Storage.EnsureRadio()) return;

            var radio = Storage.LoadRadio();
            var ver = radio.ClientVersion;

            // only applies to version 0.8.3 and earlier
            if (ver.Major > 0 ||
                ver.Minor > 8 ||
                ver.Build > 4) return;

            var stations = radio.Stations;

            // if ordinal are supplied already, then no need to do anything
            if (!stations.All(s => s.UserOrdinal == 0)) return;

            // else we fix some basic ordinal values
            for (int i = 0; i < stations.Count; i++)
                stations[i].UserOrdinal = i;

            // update version number to 0.8.4.37
            radio.ClientVersion = new Version(0, 8, 4, 37);

            Storage.SaveRadio(radio);
        }
    }
}